<?php declare(strict_types=1);
/**
 * @author      xianganyall <xianganyall@gmail.com>
 * @copyright   2023-2025 owner
 **/

namespace Srv\Libs\Frame;

use Exception;
use Smarty;
use Srv\Apps\Smarty\SmartyLink;
use Srv\Libs\Boot;
use Srv\Libs\Common\CommString;
use Srv\Libs\Common\CommValid;
use Swoole\WebSocket\Server;

abstract class ActionAbstract
{
    private ?Smarty $Smarty             = null;
    private static string $groupName    = '';

    /**
     * @return Server|null
     * getWebSocketServer
     */
    final public static function getWebSocketServer():?Server
    {
        return ResponseMain::getWebSocketServer();
    }

    /**
     * @return int
     * getWebSocketFd
     */
    final public static function getWebSocketFd():int
    {
        return ResponseMain::getWebSocketFd();
    }

    /**
     * @return string
     * getServerName
     */
    final public static function getServerName():string
    {
        return ResponseMain::getServerName();
    }

    /**
     * @return bool
     * isRelease
     */
    final public static function isRelease():bool
    {
        return Conf::getProjectConf()->isRelease();
    }

    /**
     * @param string $logString
     * @return void
     * addRunLog
     */
    final public static function addRunLog(string $logString):void
    {
        ResponseMain::addRunLog($logString);
    }

    /**
     * @param $logData
     * @return void
     * addRunLogData
     */
    final public static function addRunLogData($logData):void
    {
        ResponseMain::addRunLog(CommString::getVarString($logData));
    }

    /**
     * @return string
     * getRootPath
     */
    final public static function getRootPath():string
    {
        return Boot::getRootPath();
    }

    /**
     * @return string
     * getSrvPath
     */
    final public static function getSrvPath():string
    {
        return Boot::getSrvPath();
    }

    /**
     * @return string
     * getAppsPath
     */
    final public static function getAppsPath():string
    {
        return Boot::getAppsPath();
    }

    /**
     * @return string
     * getComposerPath
     */
    final public static function getComposerPath():string
    {
        return Boot::getComposerPath();
    }

    /**
     * @return string
     * getConfPath
     */
    final public static function getConfPath():string
    {
        return Boot::getConfPath();
    }

    /**
     * @return string
     * getLibsPath
     */
    final public static function getLibsPath():string
    {
        return Boot::getLibsPath();
    }

    /**
     * @return string
     * getDataPath
     */
    final public static function getDataPath():string
    {
        return Boot::getDataPath();
    }

    /**
     * @return string
     * getLogsPath
     */
    final public static function getLogsPath():string
    {
        return Boot::getLogsPath();
    }

    /**
     * @param string $groupName
     * @return void
     * setRouteGroupName
     */
    final public static function setRouteGroupName(string $groupName):void
    {
        self::$groupName = $groupName;
    }

    /**
     * @return string
     * getRouteGroupName
     */
    final public static function getRouteGroupName():string
    {
        return self::$groupName;
    }

    /**
     * @return string
     * getLangType
     */
    final public static function getLangType():string
    {
        return Lang::getLangType();
    }

    /**
     * @return Smarty
     * getNewSmarty
     */
    final public static function getNewSmarty():Smarty
    {
        return clone Boot::getSmartyInstance();
    }

    /**
     * @return void
     * init
     */
    final public function init():void
    {
        $this->Smarty = clone Boot::getSmartyInstance();
    }

    /**
     * @param string $actionClassName
     * @return $this
     * @throws Exception
     * getAction
     */
    final protected function getAction(string $actionClassName):self
    {
        if(!class_exists($actionClassName, true)) throw new Exception('Action ClassName Not Found, ['.$actionClassName.']');
        $actionClassObject  = new $actionClassName();
        if(!($actionClassObject instanceof self)) throw new Exception('Action ClassName Not Instanceof ActionAbstract, ['.$actionClassName.']');
        $actionClassObject->init();
        return $actionClassObject;
    }

    /**
     * @param $tplVar
     * @param $value
     * @param bool $noCache
     * @return void
     * smartyAssign
     */
    final protected function smartyAssign($tplVar, $value = null, bool $noCache = false):void
    {
        $this->Smarty->assign($tplVar, $value, $noCache);
    }

    /**
     * @param string $tplPath
     * @return string
     * smartyFetch
     */
    final protected function smartyFetch(string $tplPath):string
    {
        if(strlen($tplPath) < 1) return '';
        try{
            return strval($this->Smarty->fetch($tplPath));
        }catch (Exception $Exception){
            return '';
        }
    }

    /**
     * @param string $tplPath
     * @return string
     * smartyTplPath
     */
    private function smartyTplPath(string $tplPath):string
    {
        if(strlen($tplPath) < 1 || substr($tplPath, 0, 1) === '/' || CommValid::isPhar($tplPath)) return $tplPath;
        $classFilePath      = Boot::getClassFilePath(get_class($this));
        if(strlen($classFilePath) > 0) return dirname($classFilePath).'/Tpl/'.$tplPath;
        return $tplPath;
    }

    /**
     * @param string $tplPath
     * @return void
     * smartyShow
     */
    final protected function smartyShow(string $tplPath):void
    {
        ResponseData::rspSuccAuto($this->smartyFetch($this->smartyTplPath($tplPath)));
    }

    /**
     * @param string $tipUrl
     * @param string $tipMsg
     * @return void
     * smartyShowTips
     */
    final protected function smartyShowTips(string $tipUrl, string $tipMsg):void
    {
        $classFilePath      = Boot::getClassFilePath(SmartyLink::class);
        $tplPath            = dirname($classFilePath).'/Tpl/tips.html';
        $this->smartyAssign('systemTipMsg', $tipMsg);
        $this->smartyAssign('systemTipUrl', strlen($tipUrl) > 0 ? SmartyLink::getUrlWebRoot($tipUrl) : '');
        $this->smartyShow($tplPath);
    }

    /**
     * @param string $url
     * @return void
     * headerUrl
     */
    final protected function headerUrl(string $url):void
    {
        if(strlen($url) < 1) $url = '/';
        ResponseData::setHttpCode(307);
        ResponseData::setCustomHeader(['Location' => (CommValid::isHttps($url) || CommValid::isHttp($url)) ? $url : SmartyLink::getUrlWebRoot($url)]);
        ResponseData::rspSuccHtml('');
    }

    /**
     * @param string $limitKey
     * @param int $limitTime
     * @param int $limitNum
     * @return bool
     * limitSpeed
     */
    final protected function limitSpeed(string $limitKey, int $limitTime, int $limitNum):bool
    {
        if(strlen($limitKey) < 1 || $limitTime < 1 || $limitNum < 1) return false;
        $cacheKeyDevId  = 'LIMIT_'.md5($limitKey.'_'.$limitTime);
        $CcAuto         = ControllerAbstract::getCacheAuto();
        if($CcAuto->existsKeyNum([$cacheKeyDevId]) < 1){
            $CcAuto->setNx($cacheKeyDevId, '1', $limitTime);
        }else{
            $cacheVal   = $CcAuto->get($cacheKeyDevId);
            if($cacheVal === false) return false;
            $cacheNum   = intval($cacheVal);
            if($cacheNum < 1 || $cacheNum >= $limitNum){
                if($CcAuto->getTtl($cacheKeyDevId) === -1) $CcAuto->del($cacheKeyDevId);
                return false;
            }else{
                $CcAuto->inc($cacheKeyDevId, 1);
            }
        }
        return true;
    }
}